package org.tnc.budget.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.security.context.SecurityContextHolder;
import org.tnc.budget.dao.AttachmentTableDaoHibernate;
import org.tnc.budget.dao.EventTableDaoHibernate;
import org.tnc.budget.model.AttachmentTable;
import org.tnc.budget.model.EventTable;
import org.tnc.budget.service.EventManager;
import org.tnc.model.User;

/**
 * 约会与事件管理器
 * 
 * @author houjj | 2011-4-4 下午04:07:15
 */
public class EventManagerImpl implements EventManager, InitializingBean {

	private EventTableDaoHibernate eventTableDao;

	private AttachmentTableDaoHibernate attachmentDao;

	/**
	 * 每月六号（暂定）自动批复所有上个月未批复的工作情况。
	 */
	private int AutoReviewDayOfMonth = 6;

	public void setEventTableDao(EventTableDaoHibernate eventTableDao) {
		this.eventTableDao = eventTableDao;
	}

	public void setAttachmentDao(AttachmentTableDaoHibernate attachmentDao) {
		this.attachmentDao = attachmentDao;
	}

	public List<EventTable> getEventByMonth(int year, int month, Long name) {

		return this.eventTableDao.findEventByMonth(year, month, name);
	}

	public void saveEventTable(EventTable event) {
		eventTableDao.saveOrUpdate(event);
	}

	public void updateEventTable(EventTable event) {
		this.eventTableDao.update(event);
		this.eventTableDao.flush();
	}

	@Override
	public EventTable getEventById(int eventId) {
		EventTable et = eventTableDao.load(eventId);
		return et;
	}

	public EventTable getEventWithAttachments(int eventId) {
		EventTable et = eventTableDao.load(eventId);

		return et;
	}

	public List<EventTable> getEventByClientEventID(Long uid, String clientId) {
		List<EventTable> eventLists = eventTableDao
				.getUserEventByClientEventId(uid, clientId);

		return eventLists;
	}

	@Override
	public void deleteEventTable(EventTable event) {
		this.eventTableDao.delete(event);
	}

	@Override
	public boolean saveUnvalidEventTable(User u, String[] ids) {
		boolean result = false;
		int num = this.eventTableDao.updateEventTablesByClientIds(u.getId(),
				ids, false);
		result = (num == ids.length) ? true : false;
		return result;
	}

	@Override
	public void deleteAttachmentTable(AttachmentTable attachmentTable) {
		attachmentDao.delete(attachmentTable);
	}

	@Override
	public void deleteAttachmentTable(List<Integer> attachIds) {
		attachmentDao.deleteAttachByIds(attachIds.toArray(new Integer[0]));
	}

	@Override
	public void deleteAttachmentsByEventId(EventTable et) {

		attachmentDao.deleteAttachmentByEventId(et.getId());
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventTable> findUserEventsByTime(final String startTime,
			final String endTime, final Long userId) {
		return eventTableDao.getHibernateTemplate().executeFind(
				new HibernateCallback() {

					@Override
					public Object doInHibernate(Session s)
							throws HibernateException, SQLException {
						String sql = "SELECT * FROM event_table WHERE start_date >= ? and end_date <= ? and event_people=? and is_valid=1";
						SQLQuery q = s.createSQLQuery(sql).addEntity(
								EventTable.class);
						q.setString(0, startTime);
						q.setString(1, endTime);
						q.setLong(2, userId);
						return q.list();
					}
				});

	}

	@Override
	public AttachmentTable getAttachmentTableById(int attachmentId) {
		return (AttachmentTable) eventTableDao.getHibernateTemplate().get(
				AttachmentTable.class, attachmentId);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventTable> findUserEventsByTimeAndIds(final String startTime,
			final String endTime, final Long[] userIds) {
		if (userIds != null && userIds.length > 0)
			return eventTableDao.getHibernateTemplate().executeFind(
					new HibernateCallback() {

						@Override
						public Object doInHibernate(Session s)
								throws HibernateException, SQLException {
							String sql = "SELECT et.* from event_table et LEFT JOIN app_user au on et.event_people=au.id WHERE start_date >= ? and end_date <= ? and au.id in (:uid) and et.is_valid=1";
							SQLQuery q = s.createSQLQuery(sql).addEntity(
									EventTable.class);
							q.setString(0, startTime);
							q.setString(1, endTime);
							q.setParameterList("uid", userIds);
							return q.list();
						}
					});
		return new LinkedList<EventTable>();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventTable> findUserEventsByTimeAndBC(final String startTime,
			final String endTime, final Integer bcId) {
		return eventTableDao.getHibernateTemplate().executeFind(
				new HibernateCallback() {

					@Override
					public Object doInHibernate(Session s)
							throws HibernateException, SQLException {
						String sql = "SELECT et.* from event_table et WHERE start_date >= ? and end_date <= ? and fk_bc_id=? and is_valid=1";
						SQLQuery q = s.createSQLQuery(sql).addEntity(
								EventTable.class);
						q.setString(0, startTime);
						q.setString(1, endTime);
						q.setInteger(2, bcId);
						return q.list();
					}
				});
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EventTable> findUserEvents(final String startTime,
			final String endTime, final Integer bcId, final Long[] userIds) {

		return eventTableDao.getHibernateTemplate().executeFind(
				new HibernateCallback() {

					@Override
					public Object doInHibernate(Session s)
							throws HibernateException, SQLException {

						String sql = "SELECT et.* from event_table et LEFT JOIN app_user au on et.event_people=au.id WHERE start_date >= ? and end_date <= ? and is_valid=1";
						if (bcId != null) {
							sql += " and fk_bc_id=?";
						}
						if (userIds != null && userIds.length > 0) {
							sql += " and au.id in (:uid)";
						}

						SQLQuery q = s.createSQLQuery(sql).addEntity(
								EventTable.class);
						q.setString(0, startTime);
						q.setString(1, endTime);
						if (bcId != null) {
							q.setInteger(2, bcId);
						}
						if (userIds != null && userIds.length > 0) {
							q.setParameterList("uid", userIds);
						}
						return q.list();
					}
				});
	}

	@Override
	public void delete24HoursEvents() {
		@SuppressWarnings("unchecked")
		List<EventTable> etlist = eventTableDao.getHibernateTemplate().find(
				"from EventTable");
		for (EventTable et : etlist) {
			if (et.getDuration() >= 24.0) {
				System.err.println("Delete (duration>=24.0) event: "
						+ et.getId());
				this.deleteEventTable(et);
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void autoReviewLastMonth() {
		try {
			loadConfig();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			Calendar calendar = Calendar.getInstance();
			if (calendar.get(Calendar.DAY_OF_MONTH) >= AutoReviewDayOfMonth) {
				// 在每个月的指定日期之后，自动审批
				calendar.add(Calendar.MONTH, -1);
				calendar.set(Calendar.DAY_OF_MONTH, 1);
				final String startTime = sdf.format(calendar.getTime());
				calendar.set(Calendar.DAY_OF_MONTH,
						calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
				final String endTime = sdf.format(calendar.getTime());

				List<EventTable> etlist = eventTableDao.getHibernateTemplate()
						.executeFind(new HibernateCallback() {

							@Override
							public Object doInHibernate(Session s)
									throws HibernateException, SQLException {
								String sql = "SELECT et.* from event_table et WHERE start_date >= ? and end_date <= ? and bc_mgr_reviewed is null and is_valid=1";
								SQLQuery q = s.createSQLQuery(sql).addEntity(
										EventTable.class);
								q.setString(0, startTime);
								q.setString(1, endTime);
								return q.list();
							}
						});
				for (EventTable et : etlist) {
					et.setIsReviewed(true);
					et.setIsPassed(true);
					et.setReviewRemarks(sdf.format(new Date()) + "自动审批通过。");
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		loadConfig();
	}

	public void setAutoReviewDayOfMonth(int autoReviewDayOfMonth) {
		AutoReviewDayOfMonth = autoReviewDayOfMonth;
		saveConfig();
	}

	private File configfile = new File(System.getProperty("user.home")
			+ File.separatorChar + ".tnr.config");

	private void loadConfig() throws IOException {
		if (configfile.exists()) {
			Properties props = new Properties();
			props.load(new FileInputStream(configfile));

			this.AutoReviewDayOfMonth = Integer.parseInt(props.getProperty(
					"auto.review.day.of.month", "6"));
		} else {
			saveConfig();
		}
	}

	private void saveConfig() {
		if (!configfile.exists()) {
			try {
				configfile.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		Properties props = new Properties();
		props.setProperty("auto.review.day.of.month", "" + AutoReviewDayOfMonth);
		try {
			props.store(new FileOutputStream(configfile),
					"This is the auto generated config file for TNR.");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public int getAutoReviewDayOfMonth() {
		try {
			loadConfig();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return AutoReviewDayOfMonth;
	}

	@Override
	public void deleteEventById(Integer eventId) {
		EventTable et = getEventById(eventId);
		if (et != null) {
			User u = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
			if (et.getUser().getEmail().equalsIgnoreCase(u.getEmail())) {
				et.setIsValid(false);
			}
		}
	}

}
